package com.blue.rpc.core.annotation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.blue.rpc.util.RpcException;


public class RpcParser
{
	private static Logger logger = LoggerFactory.getLogger(RpcParser.class);

	private ApplicationContext applicationContext;
	private Map<ServiceConfig, Method> methodCache = new HashMap<>();
	private Set<Class<?>> clazzSet = new HashSet<>();
	private Set<Class<?>> interfaceSet = new HashSet<>();

	public RpcParser(ApplicationContext applicationContext)
	{
		this.applicationContext = applicationContext;
	}

	public void parse(Class<?> clazz)
	{
		if (clazzSet.contains(clazz))
			return;

		Rpc annoRpc = clazz.getAnnotation(Rpc.class);
		if (annoRpc == null)
			throw new IllegalArgumentException(clazz.getName() + " 缺少 @Rpc 注解");
		
		Component component = clazz.getAnnotation(Component.class);
		if (component == null)
			throw new IllegalArgumentException(clazz.getName() + " 缺少 @Component 注解");
		
		Class<?> interCls = annoRpc.value();
		if (interCls == null)
		{
			Class<?>[] itfs = clazz.getInterfaces();
			if (itfs.length != 1)
				throw new IllegalArgumentException(clazz.getName() + " 实现0个或多于1个接口，必须在 @Rpc 注解指定实现的接口");
			interCls = itfs[0];
		}
		else
		{
			if (!interCls.isInterface())
				throw new IllegalArgumentException(interCls.getName() + " 不是接口");
			
			if (!interCls.isAssignableFrom(clazz))
				throw new IllegalArgumentException(interCls.getName() + " 不是 " + clazz.getName() + " 的接口实现");
		}
		if (interfaceSet.contains(interCls))
			throw new IllegalArgumentException(interCls.getName() + " 不允许有多个实现");

		for (Method method : clazz.getDeclaredMethods())
		{
			if (method.getModifiers() != Modifier.PUBLIC)
				continue;
			
			this.parseMethod(clazz, interCls, method, annoRpc);
		}

		clazzSet.add(clazz);
		interfaceSet.add(interCls);
	}

	private void parseMethod(Class<?> clazz, Class<?> interCls, Method method, Rpc annoRpc)
	{
		ServiceConfig config = new ServiceConfig(interCls.getName(), method.getName());
		if (methodCache.containsKey(config))
			throw new IllegalArgumentException("已经存在：" + config);
		
		methodCache.put(config, method);
		logger.info("服务接口：{}", config);
	}

	public Object invoke(String service, String methodName, Object...params) throws Exception
	{
		ServiceConfig config = new ServiceConfig(service, methodName);
		Method method = methodCache.get(config);
		if (method == null)
			throw new RpcException("找不到方法：" + service + "." + methodName);

		Object object = applicationContext.getBean(method.getDeclaringClass());

		try
		{
			Object value = method.invoke(object, params);
			return value;
		}
		catch (Exception e)
		{
			if (e instanceof InvocationTargetException)
				e = (Exception)e.getCause();

			throw e;
		}
		
	}
	
	public Set<Class<?>> getAllInterface()
	{
		return interfaceSet;
	}

}
